<script lang="ts">
import "@milkdown/crepe/theme/common/style.css";

import { Component, Emit, Prop, Vue, Watch } from 'vue-facing-decorator';
import { Crepe } from "@milkdown/crepe";
import { markRaw, type Raw } from "vue";

@Component({
})
export default class Editor extends Vue {
  declare $refs: {
    container: HTMLDivElement;
  }
  @Prop() modelValue!: string;
  @Emit('update:modelValue') updateModelValue(value: string) {
    return value;
  }
  @Prop() readonly!: unknown;
  get isReadonly() {
    return this.readonly != null && this.readonly !== false;
  }
  crepe: Raw<Crepe> | null = null;
  
  // 工具栏按钮点击事件
  formatText(format: 'bold' | 'italic' | 'strikethrough') {
    if (!this.crepe || this.isReadonly) return;
    
    // 获取编辑器元素
    const editorElement = this.$refs.container?.querySelector('.milkdown .editor') as HTMLElement;
    if (!editorElement) return;
    
    // 确保编辑器有焦点
    editorElement.focus();
    
    // 模拟键盘快捷键
    let key: string;
    let ctrlKey = true;
    
    switch (format) {
      case 'bold':
        key = 'b';
        break;
      case 'italic':
        key = 'i';
        break;
      case 'strikethrough':
        // 删除线没有标准快捷键，我们直接插入markdown语法
        this.insertMarkdown(`~~${this.getSelectedText()}~~`);
        return;
      default:
        return;
    }
    
    // 创建并分发键盘事件
    const keyEvent = new KeyboardEvent('keydown', {
      key,
      ctrlKey,
      bubbles: true,
      cancelable: true
    });
    
    editorElement.dispatchEvent(keyEvent);
  }

  // 段落排版功能
  formatParagraph(type: 'heading' | 'quote' | 'code' | 'list' | 'hr', level?: number) {
    if (!this.crepe || this.isReadonly) return;
    
    const editorElement = this.$refs.container?.querySelector('.milkdown .editor') as HTMLElement;
    if (!editorElement) return;
    
    editorElement.focus();
    
    switch (type) {
      case 'heading':
        if (level && level >= 1 && level <= 6) {
          const hashes = '#'.repeat(level);
          this.insertMarkdown(`${hashes} `);
        }
        break;
      case 'quote':
        this.insertMarkdown('> ');
        break;
      case 'code':
        this.insertMarkdown('```\n\n```');
        break;
      case 'list':
        this.insertMarkdown('- ');
        break;
      case 'hr':
        this.insertMarkdown('\n---\n');
        break;
    }
  }

  // 插入有序列表
  insertOrderedList() {
    if (!this.crepe || this.isReadonly) return;
    this.insertMarkdown('1. ');
  }

  // 插入表格
  insertTable() {
    if (!this.crepe || this.isReadonly) return;
    const tableMarkdown = '\n| 列1 | 列2 | 列3 |\n| --- | --- | --- |\n| 内容1 | 内容2 | 内容3 |\n';
    this.insertMarkdown(tableMarkdown);
  }

  // 插入链接
  insertLink() {
    if (!this.crepe || this.isReadonly) return;
    const selectedText = this.getSelectedText();
    if (selectedText) {
      this.insertMarkdown(`[${selectedText}](链接地址)`);
    } else {
      this.insertMarkdown('[链接文本](链接地址)');
    }
  }

  // 插入图片
  insertImage() {
    if (!this.crepe || this.isReadonly) return;
    this.insertMarkdown('![图片描述](图片地址)');
  }

  // 处理标题级别选择
  handleHeadingSelect(level: number) {
    this.formatParagraph('heading', level);
  }

  // 撤销功能
  undo() {
    if (!this.crepe || this.isReadonly) return;
    
    const editorElement = this.$refs.container?.querySelector('.milkdown .editor') as HTMLElement;
    if (!editorElement) return;
    
    editorElement.focus();
    
    // 模拟Ctrl+Z
    const keyEvent = new KeyboardEvent('keydown', {
      key: 'z',
      ctrlKey: true,
      bubbles: true,
      cancelable: true
    });
    
    editorElement.dispatchEvent(keyEvent);
  }

  // 重做功能
  redo() {
    if (!this.crepe || this.isReadonly) return;
    
    const editorElement = this.$refs.container?.querySelector('.milkdown .editor') as HTMLElement;
    if (!editorElement) return;
    
    editorElement.focus();
    
    // 模拟Ctrl+Y
    const keyEvent = new KeyboardEvent('keydown', {
      key: 'y',
      ctrlKey: true,
      bubbles: true,
      cancelable: true
    });
    
    editorElement.dispatchEvent(keyEvent);
  }
  
  // 获取选中的文本
  getSelectedText(): string {
    const selection = window.getSelection();
    return selection ? selection.toString() : '';
  }
  
  // 插入markdown语法
  insertMarkdown(markdown: string) {
    const selection = window.getSelection();
    if (!selection || selection.rangeCount === 0) return;
    
    const range = selection.getRangeAt(0);
    const selectedText = range.toString();
    
    if (selectedText) {
      // 如果有选中文本，替换它
      range.deleteContents();
      range.insertNode(document.createTextNode(markdown));
    } else {
      // 如果没有选中文本，在光标位置插入
      range.insertNode(document.createTextNode(markdown));
    }
    
    // 更新markdown内容
    this.updateModelValue(this.crepe!.getMarkdown());
  }
  
  createCrepe() {
    if (this.crepe) return;
    const container = this.$refs.container;
    const root = container.appendChild(document.createElement('div'));
    root.classList.add('editor-container');
    this.crepe = markRaw(new Crepe({
      root,
      defaultValue: this.modelValue,
    }));
    this.crepe.on(listener => {
      listener.markdownUpdated(() => {
        if (!this.crepe) return;
        this.updateModelValue(this.crepe.getMarkdown());
      });
    });
    this.crepe.setReadonly(this.isReadonly);
    this.crepe.create();
  }
  disposeCrepe() {
    this.crepe?.destroy();
    this.crepe = null;
    const container = this.$refs.container;
    container.innerHTML = '';
  }
  @Watch('modelValue', { immediate: true })
  onModelValueChange() {
    if (this.crepe && this.crepe.getMarkdown() !== this.modelValue) {
      this.disposeCrepe();
      this.createCrepe();
    }
  }
  @Watch('readonly', { immediate: true })
  onReadonlyChange() {
    if (this.crepe) {
      this.crepe.setReadonly(this.isReadonly);
    }
    this.updateContainerClass();
  }
  updateContainerClass() {
    const classList = (this.$refs.container?.firstChild as HTMLElement)?.classList;
    if (classList) {
      if (this.isReadonly) classList.add('editor-readonly');
      else classList.remove('editor-readonly');
    }
  }
  mounted() {
    this.$nextTick(() => {
      this.createCrepe();
      this.updateContainerClass();
    });
  }
  beforeUnmount() {
    this.disposeCrepe();
  }
}
</script>
<template>
<div class="editor-wrap">
  <!-- 自定义工具栏 -->
  <div v-if="!isReadonly" class="editor-toolbar">
    <!-- 撤销重做 -->
    <div class="toolbar-group">
      <el-button 
        size="small" 
        @click="undo()" 
        title="撤销 (Ctrl+Z)"
        class="toolbar-btn"
      >
        <span style="font-size: 12px;">↶</span>
      </el-button>
      <el-button 
        size="small" 
        @click="redo()" 
        title="重做 (Ctrl+Y)"
        class="toolbar-btn"
      >
        <span style="font-size: 12px;">↷</span>
      </el-button>
    </div>

    <!-- 分隔线 -->
    <div class="toolbar-separator"></div>

    <!-- 文本格式 -->
    <div class="toolbar-group">
      <el-button 
        size="small" 
        @click="formatText('bold')" 
        title="加粗 (Ctrl+B)"
        class="toolbar-btn"
      >
        <strong>B</strong>
      </el-button>
      <el-button 
        size="small" 
        @click="formatText('italic')" 
        title="斜体 (Ctrl+I)"
        class="toolbar-btn"
      >
        <em>I</em>
      </el-button>
      <el-button 
        size="small" 
        @click="formatText('strikethrough')" 
        title="删除线"
        class="toolbar-btn"
      >
        <span style="text-decoration: line-through;">S</span>
      </el-button>
    </div>

    <!-- 分隔线 -->
    <div class="toolbar-separator"></div>

    <!-- 标题 -->
    <div class="toolbar-group">
      <el-dropdown @command="handleHeadingSelect" trigger="click">
        <el-button size="small" class="toolbar-btn" title="标题">
          <span style="font-weight: bold;">H</span>
        </el-button>
        <template #dropdown>
          <el-dropdown-menu>
            <el-dropdown-item :command="1">标题 1</el-dropdown-item>
            <el-dropdown-item :command="2">标题 2</el-dropdown-item>
            <el-dropdown-item :command="3">标题 3</el-dropdown-item>
            <el-dropdown-item :command="4">标题 4</el-dropdown-item>
            <el-dropdown-item :command="5">标题 5</el-dropdown-item>
            <el-dropdown-item :command="6">标题 6</el-dropdown-item>
          </el-dropdown-menu>
        </template>
      </el-dropdown>
    </div>

    <!-- 分隔线 -->
    <div class="toolbar-separator"></div>

    <!-- 列表 -->
    <div class="toolbar-group">
      <el-button 
        size="small" 
        @click="formatParagraph('list')" 
        title="无序列表"
        class="toolbar-btn"
      >
        <span style="font-size: 14px;">•</span>
      </el-button>
      <el-button 
        size="small" 
        @click="insertOrderedList()" 
        title="有序列表"
        class="toolbar-btn"
      >
        <span style="font-size: 12px;">1.</span>
      </el-button>
    </div>

    <!-- 分隔线 -->
    <div class="toolbar-separator"></div>

    <!-- 引用和代码 -->
    <div class="toolbar-group">
      <el-button 
        size="small" 
        @click="formatParagraph('quote')" 
        title="引用"
        class="toolbar-btn"
      >
        <span style="font-size: 14px;">"</span>
      </el-button>
      <el-button 
        size="small" 
        @click="formatParagraph('code')" 
        title="代码块"
        class="toolbar-btn"
      >
        <span style="font-family: monospace; font-size: 12px;">{}</span>
      </el-button>
    </div>

    <!-- 分隔线 -->
    <div class="toolbar-separator"></div>

    <!-- 链接和图片 -->
    <div class="toolbar-group">
      <el-button 
        size="small" 
        @click="insertLink()" 
        title="插入链接"
        class="toolbar-btn"
      >
        <span style="font-size: 12px;">🔗</span>
      </el-button>
      <el-button 
        size="small" 
        @click="insertImage()" 
        title="插入图片"
        class="toolbar-btn"
      >
        <span style="font-size: 12px;">🖼️</span>
      </el-button>
    </div>

    <!-- 分隔线 -->
    <div class="toolbar-separator"></div>

    <!-- 表格和分割线 -->
    <div class="toolbar-group">
      <el-button 
        size="small" 
        @click="insertTable()" 
        title="插入表格"
        class="toolbar-btn"
      >
        <span style="font-size: 12px;">📊</span>
      </el-button>
      <el-button 
        size="small" 
        @click="formatParagraph('hr')" 
        title="分割线"
        class="toolbar-btn"
      >
        <span style="font-size: 12px;">—</span>
      </el-button>
    </div>
  </div>
  <div v-once ref="container" class="editor-container-wrap">
  </div>
</div>
</template>
<style scoped>
.editor-wrap {
  display: flex;
  flex-direction: column;
}

.editor-toolbar {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 8px 12px;
  border: 1px solid var(--el-border-color-light);
  border-bottom: none;
  border-radius: var(--el-border-radius-base) var(--el-border-radius-base) 0 0;
  background-color: var(--el-bg-color-page);
  flex-wrap: wrap;
}

.toolbar-group {
  display: flex;
  gap: 2px;
}

.toolbar-separator {
  width: 1px;
  height: 20px;
  background-color: var(--el-border-color-light);
  margin: 0 2px;
}

.toolbar-btn {
  min-width: 32px;
  height: 32px;
  padding: 0 8px;
}

.toolbar-btn strong {
  font-weight: bold;
}

.toolbar-btn em {
  font-style: italic;
}

.editor-container-wrap {
  flex: 1;
}

.editor-container-wrap :deep(.editor-container) {
  width: 100%;
  min-height: 200px;
  border-radius: 0 0 var(--el-border-radius-base) var(--el-border-radius-base);
}

.editor-container-wrap :deep(.editor-container:not(.editor-readonly)) {
  border: 1px solid var(--el-border-color-light);
}

.editor-container-wrap :deep(.editor-container .milkdown > .editor) {
  padding: 10px 20px;
  min-height: 200px;
}

.tiny-mode .editor-container-wrap :deep(.editor-container .milkdown > .editor) {
  padding: 10px;
}

.editor-container-wrap :deep(.editor-container .milkdown-block-handle),
.editor-container-wrap :deep(.editor-container .crepe-placeholder::before),
.editor-container-wrap :deep(.editor-container .milkdown-slash-menu) {
  display: none;
}

/* 只读模式下的样式 */
.editor-wrap:has(.editor-readonly) .editor-toolbar {
  display: none;
}

.editor-wrap:has(.editor-readonly) .editor-container-wrap :deep(.editor-container) {
  border-radius: var(--el-border-radius-base);
}

/* 响应式设计 */
@media (max-width: 768px) {
  .editor-toolbar {
    padding: 6px 8px;
    gap: 3px;
  }
  
  .toolbar-btn {
    min-width: 28px;
    height: 28px;
    padding: 0 6px;
  }
  
  .toolbar-separator {
    height: 16px;
  }
}
</style>
